namespace OpenComposite.EII.Repository
{
	using System;
	using System.Collections.Generic;
	using System.Data;
	using System.Drawing;
	using System.IO;
	using System.Text;
	using System.Windows.Forms;
	using System.Xml;
	using System.Xml.Schema;

	using OpenComposite.EII.RepositoryUIs;

	using OpenComposite.Base;
	using OpenComposite.Base.Collections;
	using OpenComposite.Repository.Properties;

	[RepositoryItem(ItemType.Noun, "nouns", "noun_id")]
	public class Noun : RepositoryItemBaseEx
	{
		#region Initialization

		/// <summary>
		/// Initializes a new instance of the <see cref="Noun"/> class.
		/// </summary>
		public Noun()
			: base("noun_id", "noun_nm", "noun_desc", "noun_ntext", Resources.sNewNoun)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Noun"/> class.
		/// </summary>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public Noun(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Noun"/> class.
		/// </summary>
		/// <param name="id">The id.</param>
		public Noun(int id)
			: this()
		{
			this.Load(id);
		}

		#endregion Initialization

		#region Public Members

		#region Properties

		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return _LISTALLOWED; }
		}

		/// <summary>
		/// Gets or sets the type of the data.
		/// </summary>
		/// <value>The type of the data.</value>
		public string DataType
		{
			get { return getString("noun_datatype", "string"); }
			set { setValue("DataType", "noun_datatype", value); }
		}

		/// <summary>
		/// Gets the display text.
		/// </summary>
		/// <value>The display text.</value>
		public override string Display
		{
			get
			{
				string dtype = this.DataType;
				return string.Format("{0} {{{1}}}", this.Name, dtype);
			}
		}

		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override Image Image
		{
			get { return Resources.png_field; }
		}

		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "field"; }
		}

		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public override string Name
		{
			get
			{
				return base.Name;
			}
			set
			{
				if ( base.Name != value ) {
					_oldName = base.Name;
				}
				base.Name = value;
			}
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.Noun; }
		}

		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return Resources.sNoun; }
		}

		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override Image SelectedImage
		{
			get { return this.Image; }
		}

		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return "field"; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "nouns"; }
		}

		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>The type.</value>
		public NounType Type
		{
			get { return (NounType)getValue("noun_type", NounType.Noun); }
			set { setValue("Type", "noun_type", value); }
		}

		#endregion Properties

		#region Methods

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			Noun copy = new Noun(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			return copy;
		}

		/// <summary>
		/// Deletes this instance.
		/// </summary>
		/// <param name="bAsk">if set to <c>true</c> show a message to ask for deleting.</param>
		/// <returns></returns>
		public override bool Delete(bool bAsk)
		{
			string msg = "";
			BindingListEx<BusinessObject> bobjs = Global.Data.GetBusinessObjectsOfNoun(this.ID);
			if ( bobjs != null && bobjs.Count > 0 ) {
				msg = "The noun \"" + this.Name + "\" is used in one or more business objects:" + Environment.NewLine;
				foreach ( BusinessObject bo in bobjs ) {
					msg += Environment.NewLine + bo.Name;
				}
				msg += Environment.NewLine + Environment.NewLine;
				msg += "Do you really want to remove this noun from all business objects and delete it?";
			} else {
				msg = this.DeleteQuestion;
			}
			if ( !bAsk || MessageBox.Show(msg, this.RepositoryItemType.ToString(),
				 MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes ) {
				if ( bobjs != null && bobjs.Count > 0 ) {
					foreach ( BusinessObject bobj in bobjs ) {
						bobj.BeginEdit();
						foreach ( BusinessObjectField bof in bobj.BusinessObjectFields ) {
							if ( bof.NounID == this.ID ) {
								bobj.BusinessObjectFields.Remove(bof);
								break;
							}
						}
						bobj.EndEdit(true);
					}
				}
				return base.Delete(false);
			} else {
				return false;
			}
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			Bitmap bmp = new Bitmap(this.Image);
			bmp.MakeTransparent(Color.Magenta);
			return Icon.FromHandle(bmp.GetHicon());
		}

		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public override bool Save()
		{
			bool ok = base.Save();
			if ( ok && _oldName != null && _oldName != this.Name ) {
				changeNounName(_oldName, this.Name);
				_oldName = null;
			}
			return ok;
		}

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <returns></returns>
		public override DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew)
		{
			FormCreateNewNoun dlg = new FormCreateNewNoun(this, bAllowContinue);
			dlg.DomainID = idDomain;
			dlg.ShowAllFolders = false;
			dlg.ParentItem = parentItem;
			DialogResult result = dlg.ShowDialog();
			if ( result == DialogResult.OK || result == DialogResult.Retry ) {
				idDomain = dlg.DomainID;
				parentItemNew = dlg.NewParentItem;
			} else {
				idDomain = 0;
				parentItemNew = null;
			}
			return result;
		}

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString()
		{
			return string.Format("{0} {{{1}}}", this.Name, this.DataType);
		}

		#endregion Methods

		#endregion Public Members

		#region Internal Members

		#region Constant/Read-Only Fields

		internal const string ColumnDescription = "noun_desc";
		internal const string ColumnID = "noun_id";
		internal const string ColumnNText = "noun_ntext";
		internal const string ColumnName = "noun_nm";

		#endregion Constant/Read-Only Fields

		#endregion Internal Members

		#region Private Members

		#region Static Fields

		private static List<ItemType> _LISTALLOWED = new List<ItemType>();

		#endregion Static Fields

		#region Fields

		private string _oldName = null;

		#endregion Fields

		#region Methods

		private void changeNounName(string oldName, string newName)
		{
			try {
				BindingListEx<LogicalWebMethod> logMeths = Global.Data.GetLogicalMethodsOfNoun(this.ID);
				string oldPath = string.Format("/{0}</", oldName);
				string newPath = string.Format("/{0}</", newName);

				string oldInputXslt = string.Format(":{0}\"", oldName);
				string newInputXslt = string.Format(":{0}\"", newName);

				string oldOutputXslt = string.Format(":{0}>", oldName);
				string newOutputXslt = string.Format(":{0}>", newName);

				foreach ( LogicalWebMethod logMeth in logMeths ) {
					#region change input mapping
					OpenComposite.Mapper.XsltDocument xsltDoc = logMeth.InputXSLT;
					if ( xsltDoc != null ) {
						if ( xsltDoc.InnerXml.Contains(oldInputXslt) ) {
							xsltDoc.InnerXml =
								xsltDoc.InnerXml.Replace(oldInputXslt, newInputXslt);
							logMeth.InputXSLT = xsltDoc;
						}
						if ( logMeth.InputConnections.Contains(oldPath) ) {
							logMeth.InputConnections =
								logMeth.InputConnections.Replace(oldPath, newPath);
						}
					}
					#endregion
					#region change output mapping
					xsltDoc = logMeth.OutputXSLT;
					if ( xsltDoc != null ) {
						//logMeth.OutputXSLT.InnerXml =
						if ( xsltDoc.InnerXml.Contains(oldOutputXslt) ) {
							xsltDoc.InnerXml = xsltDoc.InnerXml.Replace(oldOutputXslt, newOutputXslt);
							logMeth.OutputXSLT = xsltDoc;
						}
						if ( logMeth.OutputConnections.Contains(oldPath) ) {
							logMeth.OutputConnections =
								logMeth.OutputConnections.Replace(oldPath, newPath);
						}
					}
					#endregion
					#region change proxy input mapping
					xsltDoc = logMeth.ProxyInputXSLT;
					if ( xsltDoc != null ) {
						if ( xsltDoc.InnerXml.Contains(oldInputXslt) ) {
							xsltDoc.InnerXml =
								xsltDoc.InnerXml.Replace(oldInputXslt, newInputXslt);
							logMeth.ProxyInputXSLT = xsltDoc;
						}
						if ( logMeth.ProxyInputConnections.Contains(oldPath) ) {
							logMeth.ProxyInputConnections =
								logMeth.ProxyInputConnections.Replace(oldPath, newPath);
						}
					}
					#endregion
					#region change proxy output mapping
					xsltDoc = logMeth.ProxyOutputXSLT;
					if ( xsltDoc != null ) {
						if ( xsltDoc.InnerXml.Contains(oldOutputXslt) ) {
							xsltDoc.InnerXml =
								xsltDoc.InnerXml.Replace(oldOutputXslt, newOutputXslt);
							logMeth.ProxyOutputXSLT = xsltDoc;
						}
						if ( logMeth.ProxyOutputConnections.Contains(oldPath) ) {
							logMeth.ProxyOutputConnections =
								logMeth.ProxyOutputConnections.Replace(oldPath, newPath);
						}
					}
					logMeth.Save();
					#endregion
				}
				BindingListEx<LogicalActivity> logActs = Global.Data.GetLogicalActivitiesOfNoun(this.ID);
				foreach ( LogicalActivity logAct in logActs ) {
					if ( logAct.InputXslt != null ) {
						#region change input xslt and connections
						OpenComposite.Mapper.XsltDocument xsltDoc = logAct.InputXslt;
						// left side
						if ( xsltDoc.InnerXml.Contains(oldInputXslt) ) {
							xsltDoc.InnerXml =
								xsltDoc.InnerXml.Replace(oldInputXslt, newInputXslt);
							logAct.InputXslt = xsltDoc;
						}
						// right side
						if ( xsltDoc.InnerXml.Contains(oldOutputXslt) ) {
							xsltDoc.InnerXml =
								xsltDoc.InnerXml.Replace(oldOutputXslt, newOutputXslt);
						}
						// graphical mapping
						if ( logAct.InputConnections.Contains(oldPath) ) {
							logAct.InputConnections =
								logAct.InputConnections.Replace(oldPath, newPath);
						}
						#endregion
					}
					if ( logAct.LogicalInputXslt != null ) {
						#region change logical input xslt and connections
						// left side
						if ( logAct.LogicalInputXslt.Contains(oldInputXslt) ) {
							logAct.LogicalInputXslt =
								logAct.LogicalInputXslt.Replace(oldInputXslt, newInputXslt);
						}
						// right side
						if ( logAct.LogicalInputXslt.Contains(oldOutputXslt) ) {
							logAct.LogicalInputXslt =
								logAct.LogicalInputXslt.Replace(oldOutputXslt, newOutputXslt);
						}
						// graphical mapping
						if ( logAct.LogicalInputConnections.Contains(oldPath) ) {
							logAct.LogicalInputConnections =
								logAct.LogicalInputConnections.Replace(oldPath, newPath);
						}
						#endregion
					}
					logAct.Save();
				}
				BindingListEx<BusinessObject> bos = Global.Data.GetBusinessObjectsOfNoun(this.ID);
				List<Workflow> changedWFs = new List<Workflow>();
				bool changed = false;
				foreach ( var bo in bos ) {
					BindingListEx<Workflow> wfs = Global.Data.GetWorkflowsOfBusinessObject(bo.ID);
					BindingListEx<Verb> verbs = Global.Data.GetVerbsOfBusinessObject(bo.ID);
					foreach ( var verb in verbs ) {
						wfs.AddRangeDistinct(Global.Data.GetWorkflowsOfVerb(verb.ID));
					}
					foreach ( var wf in wfs ) {
						changed = false;
						if ( !changedWFs.Contains(wf) ) {
							changedWFs.Add(wf);
							foreach ( var var in wf.ExtendedProperties.WorkflowVariables ) {
								string s = var.ParameterResolve;
								if ( s.EndsWith("." + oldName) ) {
									string newResolve = s.Substring(0, s.LastIndexOf(".") + 1) + newName;
									var.ParameterResolve = newResolve;
									changed = true;
								}
							}
							if ( changed ) wf.Save();
						}
					}
				}
			} catch ( Exception ex ) {
				System.Diagnostics.Debug.WriteLine(ex);
			}
		}

		#endregion Methods

		#endregion Private Members

		#region Enumerations

		public enum NounType
		{
			Noun = 0,
			Category
		}

		#endregion Enumerations
	}
}